using System;
using System.Collections.Generic;
using System.Text;

using Toenda.Foundation.Utility;

namespace Toenda.Foundation.Mathematics {
	/// <summary>
	/// Class
	/// </summary>
	public class Calculator {
		private string _mathQuery;
		private MathQueryParser _parser = null;

		/// <summary>
		/// Self
		/// </summary>
		public static Calculator Self = new Calculator();

		// ---------------------------------------------------
		// CONSTRUCTORS
		// ---------------------------------------------------

		/// <summary>
		/// Default Ctor
		/// </summary>
		public Calculator() {
			this._parser = new MathQueryParser();
		}

		/// <summary>
		/// Specific Ctor
		/// </summary>
		/// <param name="mathQuery">The MathQuery script string.</param>
		public Calculator(string mathQuery) {
			this._mathQuery = mathQuery;
			this._parser = new MathQueryParser(this._mathQuery);
		}

		/// <summary>
		/// Specific Ctor
		/// </summary>
		/// <param name="mathQuery">The MathQuery script string.</param>
		/// <param name="parser">The parser.</param>
		public Calculator(string mathQuery, MathQueryParser parser) {
			this._mathQuery = mathQuery;
			this._parser = parser;
		}

		// ---------------------------------------------------
		// INTERFACE IMPLEMENTATIONS
		// ---------------------------------------------------

		// ---------------------------------------------------
		// PROPERTIES
		// ---------------------------------------------------

		/// <summary>
		/// Get or set the MathQuery string
		/// </summary>
		/// <value>The math query.</value>
		public string MathQuery {
			get { return this._mathQuery; }
			set { this._mathQuery = value; }
		}

		/// <summary>
		/// Get or set the MathQueryParser
		/// </summary>
		/// <value>The parser.</value>
		public MathQueryParser Parser {
			get { return this._parser; }
			set { this._parser = value; }
		}

		// ---------------------------------------------------
		// EVENTS
		// ---------------------------------------------------

		// ---------------------------------------------------
		// PRIVATE MEMBERS
		// ---------------------------------------------------

		/// <summary>
		/// Compute a subtotal sum
		/// </summary>
		/// <param name="symbol">The symbol.</param>
		/// <param name="subtotal">The subtotal.</param>
		/// <param name="number">The number.</param>
		/// <returns></returns>
		private double _ComputeBySymbol(char symbol, double subtotal, double number) {
			switch(symbol) {
				case '+':
					//result = num1 + num2;
					subtotal += number;
					break;

				case '-':
					//result = num1 - num2;
					subtotal -= number;
					break;

				case '*':
					//result = num1 * num2;
					subtotal *= number;
					break;

				case '/':
					//result = num1 / num2;
					subtotal /= number;
					break;

				case '%':
					//result = num1 * num2;
					break;

				case '(':
					break;

				case ')':
					break;

				default:
					break;
			}

			return subtotal;
		}

		// ---------------------------------------------------
		// PROTECTED MEMBERS
		// ---------------------------------------------------

		// ---------------------------------------------------
		// PUBLIC MEMBERS
		// ---------------------------------------------------

		/// <summary>
		/// Compute a math query (read more in the documentation about the MathQuery script language)
		/// </summary>
		/// <returns></returns>
		public double Compute() {
			return this.Compute(this._mathQuery);
		}

		/// <summary>
		/// Compute a math query (read more in the documentation about the MathQuery script language)
		/// </summary>
		/// <param name="mathQuery">The MathQuery script string.</param>
		/// <returns></returns>
		public double Compute(string mathQuery) {
			double num = -1;
			//double num1 = -1;
			//double num2 = -1;
			double result = 0;
			char currentSymbol = ' ';

			string[] exposed = this._parser.Parse(mathQuery);
			List<char> mathSymbols = new List<char>(this._parser.MathSymbols);
			
			foreach(string sym in exposed) {
			    //Console.WriteLine("Symbol: " + sym);

				// get math symbol
				if(sym.Length == 1
				&& Validator.IsInList<char>(mathSymbols, Convert.ToChar(sym))) {
					char.TryParse(sym, out currentSymbol);

					//Console.WriteLine(" ---> currentSymbol: " + currentSymbol.ToString());

					// compute by default symbols: +, -, *, /, %, (, )
					if(num != -1) {
						result = this._ComputeBySymbol(currentSymbol, result, num);
						num = -1;
					}
				}
				else {
					//Console.WriteLine(" ........... number : " + sym.ToString());

					double.TryParse(sym, out num);

					// compute by default symbols: +, -, *, /, %, (, )
					if(Validator.IsSet<char>(currentSymbol) 
					&& currentSymbol != ' '
					&& num != -1) {
						result = this._ComputeBySymbol(currentSymbol, result, num);
						num = -1;
					}

					//if(num1 == -1) {
					//    double.TryParse(sym, out num1);
					//}
					//else {
					//    double.TryParse(sym, out num2);
					//}
				}

				//Console.WriteLine("------------------------------------------Subtotal: " + result.ToString());

				//}
				//else {
				//    // get number
				//    Console.WriteLine(" ........... number : " + sym);

				//    double.TryParse(sym, out num);

				//    //if(num1 == -1) {
				//    //    double.TryParse(sym, out num1);
				//    //}
				//    //else {
				//    //    double.TryParse(sym, out num2);
				//    //}
				//}
			}

			// TODO: For the first time, the parser comes here

			return result;
		}
	}
}
